package cn.piggy.gateway.core.socket.handler;

import cn.piggy.gateway.common.model.LoginUser;
import cn.piggy.gateway.common.util.JwtUtil;
import cn.piggy.gateway.core.http.HttpStatement;
import cn.piggy.gateway.core.limiter.RedisLimiter;
import cn.piggy.gateway.core.socket.common.AgreementConstant;
import cn.piggy.gateway.core.socket.common.GatewayResult;
import cn.piggy.gateway.core.socket.parser.ResponseParser;
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.concurrent.TimeUnit;


public class AuthorizationHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private final Logger logger = LoggerFactory.getLogger(AuthorizationHandler.class);

    public AuthorizationHandler() {}

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        Channel channel = ctx.channel();
        logger.info("网关接收请求【鉴权】 uri：{} method：{}", request.uri(), request.method());
        try {
            HttpStatement httpStatement = channel.attr(AgreementConstant.HTTP_STATEMENT).get();
            if (httpStatement.isAuth()) {
                try {
                    // 鉴权信息
                    String token = request.headers().get("token");
                    // 鉴权判断
                    if (checkToken(token, httpStatement.getRole())) {
                        request.retain();
                        ctx.fireChannelRead(request);
                    } else {
                        DefaultFullHttpResponse response = new ResponseParser().parse(GatewayResult.buildError(AgreementConstant.ResponseCode._403.getCode(), "对不起，你无权访问此接口！"));
                        channel.writeAndFlush(response);
                    }
                } catch (Exception e) {
                    DefaultFullHttpResponse response = new ResponseParser().parse(GatewayResult.buildError(AgreementConstant.ResponseCode._403.getCode(), "对不起，你的鉴权不合法！"));
                    channel.writeAndFlush(response);
                }
            }
            // 不鉴权放行
            else {
                request.retain();
                ctx.fireChannelRead(request);
            }
        } catch (Exception e) {
            // 4. 封装返回结果
            DefaultFullHttpResponse response = new ResponseParser().parse(GatewayResult.buildError(AgreementConstant.ResponseCode._500.getCode(), "网关协议调用失败！" + e.getMessage()));
            channel.writeAndFlush(response);
        }
    }

    private boolean checkToken(String token,String role){
        if (null == token || "".equals(token)) {
            return false;
        }
        String subject = JwtUtil.decode(token).getSubject();
        RedissonClient redissonClient = RedisLimiter.getRedissonClient();
        String body = redissonClient.getBucket(subject).get().toString();
        LoginUser loginUser = JSON.parseObject(body, LoginUser.class);
        Long expireTime = loginUser.getExpireTime();
        if(expireTime < System.currentTimeMillis()){
            return false;
        }
        Set<String> roles = loginUser.getRoles();
        if(roles.contains(role)){
            verifyToken(loginUser);
            return true;
        }
        return false;
    }
    public void verifyToken(LoginUser loginUser) {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= 10*60*1000) {
            refreshToken(loginUser);
        }
    }
    public void refreshToken(LoginUser loginUser) {
        loginUser.setExpireTime(System.currentTimeMillis() + 60*60*1000);
        String token = loginUser.getToken();
        RedissonClient redissonClient = RedisLimiter.getRedissonClient();
        redissonClient.getBucket(token).set(JSON.toJSONString(loginUser),1,TimeUnit.HOURS);
    }
}
